use of com.sun.source.util.TreePath in project error-prone by google.
the class AbstractMustBeClosedChecker method checkClosed.
private Description checkClosed(ExpressionTree tree, VisitorState state) {
MethodTree callerMethodTree = enclosingMethod(state);
TreePath path = state.getPath();
OUTER: while (true) {
TreePath prev = path;
path = path.getParentPath();
switch(path.getLeaf().getKind()) {
case RETURN:
if (callerMethodTree != null) {
// expression or anonymous class.
if (HAS_MUST_BE_CLOSED_ANNOTATION.matches(callerMethodTree, state)) {
// enforced.
return NO_MATCH;
}
// enforced. Suggest fixing this by annotating the caller method.
return buildDescription(tree).addFix(SuggestedFix.builder().prefixWith(callerMethodTree, "@MustBeClosed\n").addImport(MustBeClosed.class.getCanonicalName()).build()).build();
}
break;
case CONDITIONAL_EXPRESSION:
ConditionalExpressionTree conditionalExpressionTree = (ConditionalExpressionTree) path.getLeaf();
if (conditionalExpressionTree.getTrueExpression().equals(prev.getLeaf()) || conditionalExpressionTree.getFalseExpression().equals(prev.getLeaf())) {
continue OUTER;
}
break;
case MEMBER_SELECT:
MemberSelectTree memberSelectTree = (MemberSelectTree) path.getLeaf();
if (memberSelectTree.getExpression().equals(prev.getLeaf())) {
Type type = getType(memberSelectTree);
Symbol sym = getSymbol(memberSelectTree);
Type streamType = state.getTypeFromString(Stream.class.getName());
if (isSubtype(sym.enclClass().asType(), streamType, state) && isSameType(type.getReturnType(), streamType, state)) {
// skip enclosing method invocation
path = path.getParentPath();
continue OUTER;
}
}
break;
case VARIABLE:
Symbol sym = getSymbol(path.getLeaf());
if (sym instanceof VarSymbol) {
VarSymbol var = (VarSymbol) sym;
if (var.getKind() == ElementKind.RESOURCE_VARIABLE || tryFinallyClose(var, path, state)) {
return NO_MATCH;
}
}
break;
default:
break;
}
// The constructor or method invocation does not occur within the resource variable
// initializer of a try-with-resources statement.
Description.Builder description = buildDescription(tree);
addFix(description, tree, state);
return description.build();
}
}
use of com.sun.source.util.TreePath in project error-prone by google.
the class FindIdentifiers method isVisible.
private static boolean isVisible(VarSymbol var, final TreePath path) {
switch(var.getKind()) {
case ENUM_CONSTANT:
case FIELD:
// TODO(eaftan): Switch collector to ImmutableList.toImmutableList() when released
List<ClassSymbol> enclosingClasses = StreamSupport.stream(path.spliterator(), false).filter(tree -> tree instanceof ClassTree).map(ClassTree.class::cast).map(ASTHelpers::getSymbol).collect(Collectors.toCollection(ArrayList::new));
if (!var.isStatic()) {
// Instance fields are not visible if we are in a static context...
if (inStaticContext(path)) {
return false;
}
// the enclosing static nested class (JLS 8.5.1).
if (lowerThan(path, (curr, unused) -> curr instanceof ClassTree && ASTHelpers.getSymbol((ClassTree) curr).isStatic(), (curr, unused) -> curr instanceof ClassTree && ASTHelpers.getSymbol((ClassTree) curr).equals(var.owner))) {
return false;
}
}
// fields (JLS 6.6.1).
if (enclosingClasses.contains(ASTHelpers.enclosingClass(var))) {
return true;
}
PackageSymbol enclosingPackage = ((JCCompilationUnit) path.getCompilationUnit()).packge;
Set<Modifier> modifiers = var.getModifiers();
// (JLS 6.6.1).
if (Objects.equals(enclosingPackage, ASTHelpers.enclosingPackage(var))) {
return !modifiers.contains(Modifier.PRIVATE);
}
// in the enclosing class or a superclass).
return modifiers.contains(Modifier.PUBLIC) || modifiers.contains(Modifier.PROTECTED);
case PARAMETER:
case LOCAL_VARIABLE:
// final or effectively final (JLS 8.1.3).
if (lowerThan(path, (curr, parent) -> curr.getKind() == Kind.LAMBDA_EXPRESSION || (curr.getKind() == Kind.NEW_CLASS && ((NewClassTree) curr).getClassBody() != null) || (curr.getKind() == Kind.CLASS && parent.getKind() == Kind.BLOCK), (curr, unused) -> Objects.equals(var.owner, ASTHelpers.getSymbol(curr)))) {
if ((var.flags() & (Flags.FINAL | Flags.EFFECTIVELY_FINAL)) == 0) {
return false;
}
}
return true;
case EXCEPTION_PARAMETER:
case RESOURCE_VARIABLE:
return true;
default:
throw new IllegalArgumentException("Unexpected variable type: " + var.getKind());
}
}
use of com.sun.source.util.TreePath in project error-prone by google.
the class ErrorProneAnalyzer method finished.
@Override
public void finished(TaskEvent taskEvent) {
if (taskEvent.getKind() != Kind.ANALYZE) {
return;
}
if (JavaCompiler.instance(context).errorCount() > 0) {
return;
}
TreePath path = JavacTrees.instance(context).getPath(taskEvent.getTypeElement());
if (path == null) {
path = new TreePath(taskEvent.getCompilationUnit());
}
// Assert that the event is unique and scan the current tree.
verify(seen.add(path.getLeaf()), "Duplicate FLOW event for: %s", taskEvent.getTypeElement());
Context subContext = new SubContext(context);
subContext.put(ErrorProneOptions.class, errorProneOptions);
Log log = Log.instance(context);
JCCompilationUnit compilation = (JCCompilationUnit) path.getCompilationUnit();
DescriptionListener descriptionListener = descriptionListenerFactory.getDescriptionListener(log, compilation);
JavaFileObject originalSource = log.useSource(compilation.getSourceFile());
try {
if (shouldExcludeSourceFile(compilation.getSourceFile())) {
return;
}
if (path.getLeaf().getKind() == Tree.Kind.COMPILATION_UNIT) {
// We only get TaskEvents for compilation units if they contain no package declarations
// (e.g. package-info.java files). In this case it's safe to analyze the
// CompilationUnitTree immediately.
transformer.get().apply(path, subContext, descriptionListener);
} else if (finishedCompilation(path.getCompilationUnit())) {
// Otherwise this TaskEvent is for a ClassTree, and we can scan the whole
// CompilationUnitTree once we've seen all the enclosed classes.
transformer.get().apply(new TreePath(compilation), subContext, descriptionListener);
}
} catch (ErrorProneError e) {
e.logFatalError(log);
// terminate with Result.ABNORMAL
throw e;
} catch (CompletionFailure e) {
// A CompletionFailure can be triggered when error-prone tries to complete a symbol
// that isn't on the compilation classpath. This can occur when a check performs an
// instanceof test on a symbol, which requires inspecting the transitive closure of the
// symbol's supertypes. If javac didn't need to check the symbol's assignability
// then a normal compilation would have succeeded, and no diagnostics will have been
// reported yet, but we don't want to crash javac.
log.error("proc.cant.access", e.sym, e.getDetailValue(), Throwables.getStackTraceAsString(e));
} finally {
log.useSource(originalSource);
}
}
use of com.sun.source.util.TreePath in project error-prone by google.
the class NullnessPropagationTransfer method fieldInitializerNullnessIfAvailable.
@Nullable
private Nullness fieldInitializerNullnessIfAvailable(ClassAndField accessed) {
if (!traversed.add(accessed.symbol)) {
// TODO(kmb): Try to recognize problems with initialization order
return NULL;
}
try {
JavacProcessingEnvironment javacEnv = JavacProcessingEnvironment.instance(context);
TreePath fieldDeclPath = Trees.instance(javacEnv).getPath(accessed.symbol);
// missing types.
if (fieldDeclPath == null || fieldDeclPath.getCompilationUnit() != compilationUnit || !(fieldDeclPath.getLeaf() instanceof VariableTree)) {
return null;
}
ExpressionTree initializer = ((VariableTree) fieldDeclPath.getLeaf()).getInitializer();
if (initializer == null) {
return null;
}
ClassTree classTree = (ClassTree) fieldDeclPath.getParentPath().getLeaf();
// Run flow analysis on field initializer. This is inefficient compared to just walking
// the initializer expression tree but it avoids duplicating the logic from this transfer
// function into a method that operates on Javac Nodes.
TreePath initializerPath = TreePath.getPath(fieldDeclPath, initializer);
UnderlyingAST ast = new UnderlyingAST.CFGStatement(initializerPath.getLeaf(), classTree);
ControlFlowGraph cfg = CFGBuilder.build(initializerPath, javacEnv, ast, /* assumeAssertionsEnabled */
false, /* assumeAssertionsDisabled */
false);
Analysis<Nullness, LocalStore<Nullness>, NullnessPropagationTransfer> analysis = new Analysis<>(javacEnv, this);
analysis.performAnalysis(cfg);
return analysis.getValue(initializerPath.getLeaf());
} finally {
traversed.remove(accessed.symbol);
}
}
use of com.sun.source.util.TreePath in project error-prone by google.
the class TrustingNullnessAnalysis method getFieldInitializerNullness.
/**
* Returns {@link Nullness} of the initializer of the {@link VariableTree} at the leaf of the
* given {@code fieldDeclPath}. Returns {@link Nullness#NULL} should there be no initializer.
*/
// TODO(kmb): Fold this functionality into Dataflow.expressionDataflow
public Nullness getFieldInitializerNullness(TreePath fieldDeclPath, Context context) {
Tree decl = fieldDeclPath.getLeaf();
checkArgument(decl instanceof VariableTree && ((JCVariableDecl) decl).sym.getKind() == ElementKind.FIELD, "Leaf of fieldDeclPath must be a field declaration: %s", decl);
ExpressionTree initializer = ((VariableTree) decl).getInitializer();
if (initializer == null) {
// An uninitialized field is null or 0 to start :)
return ((JCVariableDecl) decl).type.isPrimitive() ? Nullness.NONNULL : Nullness.NULL;
}
TreePath initializerPath = TreePath.getPath(fieldDeclPath, initializer);
ClassTree classTree = (ClassTree) fieldDeclPath.getParentPath().getLeaf();
JavacProcessingEnvironment javacEnv = JavacProcessingEnvironment.instance(context);
UnderlyingAST ast = new UnderlyingAST.CFGStatement(decl, classTree);
ControlFlowGraph cfg = CFGBuilder.build(initializerPath, javacEnv, ast, /* assumeAssertionsEnabled */
false, /* assumeAssertionsDisabled */
false);
try {
nullnessPropagation.setContext(context).setCompilationUnit(fieldDeclPath.getCompilationUnit());
Analysis<Nullness, LocalStore<Nullness>, TrustingNullnessPropagation> analysis = new Analysis<>(javacEnv, nullnessPropagation);
analysis.performAnalysis(cfg);
return analysis.getValue(initializer);
} finally {
nullnessPropagation.setContext(null).setCompilationUnit(null);
}
}
Aggregations