1 /*******************************************************************************
2  * Copyright (c) 2008, 2013 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.pde.api.tools.internal.builder;
15 
16 import java.util.Set;
17 
18 import org.eclipse.core.runtime.CoreException;
19 import org.eclipse.jdt.core.Flags;
20 import org.eclipse.jdt.core.IField;
21 import org.eclipse.jdt.core.ISourceRange;
22 import org.eclipse.jdt.core.IType;
23 import org.eclipse.jface.text.BadLocationException;
24 import org.eclipse.jface.text.IDocument;
25 import org.eclipse.jface.text.Position;
26 import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
27 import org.eclipse.pde.api.tools.internal.provisional.IApiAnnotations;
28 import org.eclipse.pde.api.tools.internal.provisional.IApiDescription;
29 import org.eclipse.pde.api.tools.internal.provisional.RestrictionModifiers;
30 import org.eclipse.pde.api.tools.internal.provisional.builder.IReference;
31 import org.eclipse.pde.api.tools.internal.provisional.descriptors.IElementDescriptor;
32 import org.eclipse.pde.api.tools.internal.provisional.model.IApiField;
33 import org.eclipse.pde.api.tools.internal.provisional.model.IApiType;
34 import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem;
35 import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblemTypes;
36 
37 /**
38  * Detects leaked field declarations (declared type).
39  *
40  * @since 1.1
41  */
42 public class LeakFieldProblemDetector extends AbstractTypeLeakDetector {
43 
44 	/**
45 	 * @param nonApiPackageNames
46 	 */
LeakFieldProblemDetector(Set<String> nonApiPackageNames)47 	public LeakFieldProblemDetector(Set<String> nonApiPackageNames) {
48 		super(nonApiPackageNames);
49 	}
50 
51 	@Override
isApplicable(IApiAnnotations annotations)52 	protected boolean isApplicable(IApiAnnotations annotations) {
53 		return super.isApplicable(annotations) && !RestrictionModifiers.isReferenceRestriction(annotations.getRestrictions());
54 	}
55 
56 	@Override
getReferenceKinds()57 	public int getReferenceKinds() {
58 		return IReference.REF_FIELDDECL;
59 	}
60 
61 	@Override
getElementType(IReference reference)62 	protected int getElementType(IReference reference) {
63 		return IElementDescriptor.FIELD;
64 	}
65 
66 	@Override
getSeverityKey()67 	protected String getSeverityKey() {
68 		return IApiProblemTypes.LEAK_FIELD_DECL;
69 	}
70 
71 	@Override
getProblemFlags(IReference reference)72 	protected int getProblemFlags(IReference reference) {
73 		return IApiProblem.LEAK_FIELD;
74 	}
75 
76 	@Override
isProblem(IReference reference)77 	protected boolean isProblem(IReference reference) {
78 		if (super.isProblem(reference)) {
79 			IApiField field = (IApiField) reference.getMember();
80 			if ((Flags.AccProtected & field.getModifiers()) > 0) {
81 				// TODO: could do this check before resolution - it's a check on
82 				// the source location
83 				// ignore protected members if contained in a @noextend type
84 				try {
85 					IApiDescription description = field.getApiComponent().getApiDescription();
86 					IApiAnnotations annotations = description.resolveAnnotations(field.getHandle().getEnclosingType());
87 					if (annotations == null || RestrictionModifiers.isExtendRestriction(annotations.getRestrictions())) {
88 						return false;
89 					}
90 				} catch (CoreException e) {
91 					ApiPlugin.log(e);
92 				}
93 			}
94 			return true;
95 		}
96 		return false;
97 	}
98 
99 	@Override
getMessageArgs(IReference reference)100 	protected String[] getMessageArgs(IReference reference) throws CoreException {
101 		IApiField field = (IApiField) reference.getMember();
102 		IApiType type = (IApiType) reference.getResolvedReference();
103 		return new String[] {
104 				getSimpleTypeName(type), getSimpleTypeName(field),
105 				field.getName() };
106 	}
107 
108 	@Override
getQualifiedMessageArgs(IReference reference)109 	protected String[] getQualifiedMessageArgs(IReference reference) throws CoreException {
110 		IApiField field = (IApiField) reference.getMember();
111 		IApiType type = (IApiType) reference.getResolvedReference();
112 		return new String[] {
113 				getQualifiedTypeName(type), getQualifiedTypeName(field),
114 				field.getName() };
115 	}
116 
117 	@Override
getSourceRange(IType type, IDocument doc, IReference reference)118 	protected Position getSourceRange(IType type, IDocument doc, IReference reference) throws CoreException, BadLocationException {
119 		IApiField field = (IApiField) reference.getMember();
120 		IField javaField = type.getField(field.getName());
121 		Position pos = null;
122 		if (javaField.exists()) {
123 			ISourceRange range = javaField.getNameRange();
124 			if (range != null) {
125 				pos = new Position(range.getOffset(), range.getLength());
126 			}
127 		}
128 		if (pos == null) {
129 			return defaultSourcePosition(type, reference);
130 		}
131 		return pos;
132 	}
133 }
134