blob: ffd8b32141c83d7c09d91e39942fa63824cbc852 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.java.hints.declarative;
import com.sun.source.tree.BlockTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree.Kind;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.netbeans.api.lexer.TokenHierarchy;
import org.netbeans.api.lexer.TokenSequence;
import org.netbeans.modules.java.hints.declarative.Condition.Otherwise;
import org.netbeans.modules.java.hints.declarative.conditionapi.Context;
import org.netbeans.modules.java.hints.providers.spi.HintDescription.Worker;
import org.netbeans.modules.java.hints.spiimpl.JavaFixImpl;
import org.netbeans.spi.editor.hints.ErrorDescription;
import org.netbeans.spi.editor.hints.Fix;
import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
import org.netbeans.spi.java.hints.HintContext;
import org.netbeans.spi.java.hints.HintContext.MessageKind;
import org.netbeans.spi.java.hints.JavaFixUtilities;
import org.openide.util.NbBundle.Messages;
/**
*
* @author Jan Lahoda
*/
class DeclarativeHintsWorker implements Worker {
private final String displayName;
private final String pattern;
private final List<Condition> conditions;
private final String imports;
private final List<DeclarativeFix> fixes;
private final Map<String, String> options;
public DeclarativeHintsWorker(String displayName, String pattern, List<Condition> conditions, String imports, List<DeclarativeFix> fixes, Map<String, String> options) {
this.displayName = displayName;
this.pattern = pattern;
this.conditions = conditions;
this.imports = imports;
this.fixes = fixes;
this.options = options;
}
//for tests:
String getDisplayName() {
return displayName;
}
//for tests:
List<DeclarativeFix> getFixes() {
return fixes;
}
@Messages("FIX_RemoveFromParent=Remove {0} from parent")
@Override
public Collection<? extends ErrorDescription> createErrors(HintContext ctx) {
Context context = new Context(ctx);
context.enterScope();
for (Condition c : conditions) {
if (!c.holds(context, true)) {
return null;
}
}
List<Fix> editorFixes = new LinkedList<Fix>();
OUTER: for (DeclarativeFix fix : fixes) {
context.enterScope();
try {
for (Condition c : fix.getConditions()) {
if (c instanceof Otherwise) {
if (editorFixes.isEmpty()) {
continue;
} else {
continue OUTER;
}
}
if (!c.holds(context, false)) {
continue OUTER;
}
}
reportErrorWarning(ctx, fix.getOptions());
TokenSequence<DeclarativeHintTokenId> ts = TokenHierarchy.create(fix.getPattern(),
false,
DeclarativeHintTokenId.language(),
EnumSet.of(DeclarativeHintTokenId.BLOCK_COMMENT,
DeclarativeHintTokenId.LINE_COMMENT,
DeclarativeHintTokenId.WHITESPACE),
null).tokenSequence(DeclarativeHintTokenId.language());
boolean empty = !ts.moveNext();
if (empty) {
if ( ( !fix.getOptions().containsKey(DeclarativeHintsOptions.OPTION_ERROR)
&& !fix.getOptions().containsKey(DeclarativeHintsOptions.OPTION_WARNING))
|| fix.getOptions().containsKey(DeclarativeHintsOptions.OPTION_REMOVE_FROM_PARENT)) {
editorFixes.add(JavaFixUtilities.removeFromParent(ctx, Bundle.FIX_RemoveFromParent(/*TODO: better short name:*/ctx.getPath().getLeaf().toString()), ctx.getPath()));
}
//not realizing empty fixes
} else {
editorFixes.add(JavaFixImpl.Accessor.INSTANCE.rewriteFix(ctx.getInfo(),
fix.getDisplayName(),
ctx.getPath(),
fix.getPattern(),
APIAccessor.IMPL.getVariables(context),
APIAccessor.IMPL.getMultiVariables(context),
APIAccessor.IMPL.getVariableNames(context),
ctx.getConstraints(),
fix.getOptions(),
imports));
}
} finally {
context.leaveScope();
}
}
context.leaveScope();
// if (primarySuppressWarningsKey != null && primarySuppressWarningsKey.length() > 0) {
// editorFixes.addAll(FixFactory.createSuppressWarnings(ctx.getInfo(), ctx.getPath(), primarySuppressWarningsKey));
// }
Tree errorTree = ctx.getPath().getLeaf();
if (errorTree.getKind() == Kind.BLOCK) {
Tree parsedPattern = org.netbeans.modules.java.hints.spiimpl.Utilities.parseAndAttribute(ctx.getInfo(), pattern, null);
if (org.netbeans.modules.java.hints.spiimpl.Utilities.isFakeBlock(parsedPattern)) {
BlockTree fakeBlock = (BlockTree) parsedPattern;
Tree firstStatement = !fakeBlock.getStatements().isEmpty() ? fakeBlock.getStatements().get(0) : null;
String leadingName = firstStatement != null ? org.netbeans.modules.java.hints.spiimpl.Utilities.getWildcardTreeName(firstStatement).toString() : null;
if (leadingName != null) {
int skip;
if (ctx.getMultiVariables().get(leadingName) != null) {
skip = ctx.getMultiVariables().get(leadingName).size();
} else if (ctx.getVariables().get(leadingName) != null) {
skip = 1;
} else {
skip = 0;
}
BlockTree errorBlock = (BlockTree) errorTree;
if (skip < errorBlock.getStatements().size()) {
errorTree = errorBlock.getStatements().get(skip);
}
}
}
}
ErrorDescription ed = ErrorDescriptionFactory.forName(ctx, errorTree, displayName, editorFixes.toArray(new Fix[0]));
if (ed == null) {
return null;
}
return Collections.singletonList(ed);
}
private static void reportErrorWarning(HintContext ctx, Map<String, String> options) {
String errorText = options.get("error");
if (errorText != null) {
ctx.reportMessage(MessageKind.ERROR, errorText);
}
String warningText = options.get("warning");
if (warningText != null) {
ctx.reportMessage(MessageKind.WARNING, warningText);
}
}
}