raster@14180
|
1 |
/*
|
raster@14180
|
2 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
|
raster@14180
|
3 |
*
|
raster@14180
|
4 |
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
|
raster@14180
|
5 |
*
|
raster@14180
|
6 |
* The contents of this file are subject to the terms of either the GNU
|
raster@14180
|
7 |
* General Public License Version 2 only ("GPL") or the Common
|
raster@14180
|
8 |
* Development and Distribution License("CDDL") (collectively, the
|
raster@14180
|
9 |
* "License"). You may not use this file except in compliance with the
|
raster@14180
|
10 |
* License. You can obtain a copy of the License at
|
raster@14180
|
11 |
* http://www.netbeans.org/cddl-gplv2.html
|
raster@14180
|
12 |
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
|
raster@14180
|
13 |
* specific language governing permissions and limitations under the
|
raster@14180
|
14 |
* License. When distributing the software, include this License Header
|
raster@14180
|
15 |
* Notice in each file and include the License file at
|
raster@14180
|
16 |
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
|
raster@14180
|
17 |
* particular file as subject to the "Classpath" exception as provided
|
raster@14180
|
18 |
* by Sun in the GPL Version 2 section of the License file that
|
raster@14180
|
19 |
* accompanied this code. If applicable, add the following below the
|
raster@14180
|
20 |
* License Header, with the fields enclosed by brackets [] replaced by
|
raster@14180
|
21 |
* your own identifying information:
|
raster@14180
|
22 |
* "Portions Copyrighted [year] [name of copyright owner]"
|
raster@14180
|
23 |
*
|
raster@14180
|
24 |
* If you wish your version of this file to be governed by only the CDDL
|
raster@14180
|
25 |
* or only the GPL Version 2, indicate your decision by adding
|
raster@14180
|
26 |
* "[Contributor] elects to include this software in this distribution
|
raster@14180
|
27 |
* under the [CDDL or GPL Version 2] license." If you do not indicate a
|
raster@14180
|
28 |
* single choice of license, a recipient has the option to distribute
|
raster@14180
|
29 |
* your version of this file under either the CDDL, the GPL Version 2 or
|
raster@14180
|
30 |
* to extend the choice of license to its licensees as provided above.
|
raster@14180
|
31 |
* However, if you add GPL Version 2 code and therefore, elected the GPL
|
raster@14180
|
32 |
* Version 2 license, then the option applies only if the new code is
|
raster@14180
|
33 |
* made subject to such option by the copyright holder.
|
raster@14180
|
34 |
*
|
raster@14180
|
35 |
* Contributor(s):
|
raster@14180
|
36 |
*
|
raster@14180
|
37 |
* Portions Copyrighted 2008 Sun Microsystems, Inc.
|
raster@14180
|
38 |
*/
|
raster@14180
|
39 |
package org.netbeans.modules.ada.editor.parser;
|
raster@14180
|
40 |
|
raster@14523
|
41 |
import java.util.ArrayList;
|
raster@14523
|
42 |
import java.util.EnumSet;
|
raster@14523
|
43 |
import java.util.HashMap;
|
raster@14523
|
44 |
import java.util.List;
|
raster@14180
|
45 |
import java.util.Map;
|
raster@14180
|
46 |
import java.util.Set;
|
raster@16367
|
47 |
import java.util.logging.Level;
|
raster@16367
|
48 |
import java.util.logging.Logger;
|
raster@14523
|
49 |
import org.netbeans.modules.ada.editor.ast.ASTNode;
|
raster@14523
|
50 |
import org.netbeans.modules.ada.editor.ast.nodes.Block;
|
raster@14695
|
51 |
import org.netbeans.modules.ada.editor.ast.nodes.BodyDeclaration.Modifier;
|
raster@14539
|
52 |
import org.netbeans.modules.ada.editor.ast.nodes.FieldsDeclaration;
|
raster@14523
|
53 |
import org.netbeans.modules.ada.editor.ast.nodes.Identifier;
|
raster@14695
|
54 |
import org.netbeans.modules.ada.editor.ast.nodes.MethodDeclaration;
|
raster@14523
|
55 |
import org.netbeans.modules.ada.editor.ast.nodes.PackageBody;
|
raster@14523
|
56 |
import org.netbeans.modules.ada.editor.ast.nodes.PackageSpecification;
|
raster@14695
|
57 |
import org.netbeans.modules.ada.editor.ast.nodes.TypeDeclaration;
|
raster@16367
|
58 |
import org.netbeans.modules.ada.editor.ast.nodes.TypeName;
|
raster@14539
|
59 |
import org.netbeans.modules.ada.editor.ast.nodes.Variable;
|
raster@14523
|
60 |
import org.netbeans.modules.ada.editor.ast.nodes.visitors.DefaultVisitor;
|
raster@15779
|
61 |
import org.netbeans.modules.csl.api.ColoringAttributes;
|
raster@15779
|
62 |
import org.netbeans.modules.csl.api.OffsetRange;
|
raster@15779
|
63 |
import org.netbeans.modules.csl.api.SemanticAnalyzer;
|
raster@15779
|
64 |
import org.netbeans.modules.csl.spi.ParserResult;
|
raster@15779
|
65 |
import org.netbeans.modules.parsing.api.Snapshot;
|
raster@15779
|
66 |
import org.netbeans.modules.parsing.spi.Parser.Result;
|
raster@15779
|
67 |
import org.netbeans.modules.parsing.spi.Scheduler;
|
raster@15779
|
68 |
import org.netbeans.modules.parsing.spi.SchedulerEvent;
|
raster@14180
|
69 |
|
raster@14180
|
70 |
/**
|
raster@14539
|
71 |
* Based on org.netbeans.modules.php.editor.parser.SemanticAnalysis
|
raster@14180
|
72 |
*
|
raster@14180
|
73 |
* @author Andrea Lucarelli
|
raster@14180
|
74 |
*/
|
raster@15779
|
75 |
public class AdaSemanticAnalyzer extends SemanticAnalyzer {
|
raster@14180
|
76 |
|
raster@16367
|
77 |
private static final Logger LOGGER = Logger.getLogger(AdaSemanticAnalyzer.class.getName());
|
raster@16367
|
78 |
|
raster@14523
|
79 |
public static final EnumSet<ColoringAttributes> UNUSED_FIELD_SET = EnumSet.of(ColoringAttributes.UNUSED, ColoringAttributes.FIELD);
|
raster@14523
|
80 |
public static final EnumSet<ColoringAttributes> UNUSED_METHOD_SET = EnumSet.of(ColoringAttributes.UNUSED, ColoringAttributes.METHOD);
|
raster@14523
|
81 |
private boolean cancelled;
|
raster@14523
|
82 |
private Map<OffsetRange, Set<ColoringAttributes>> semanticHighlights;
|
raster@14523
|
83 |
|
raster@14523
|
84 |
public AdaSemanticAnalyzer() {
|
raster@14523
|
85 |
semanticHighlights = null;
|
raster@16367
|
86 |
LOGGER.setLevel(Level.FINE);
|
raster@14523
|
87 |
}
|
raster@14523
|
88 |
|
raster@14180
|
89 |
public Map<OffsetRange, Set<ColoringAttributes>> getHighlights() {
|
raster@14523
|
90 |
return semanticHighlights;
|
raster@14180
|
91 |
}
|
raster@14180
|
92 |
|
raster@14180
|
93 |
public void cancel() {
|
raster@14523
|
94 |
cancelled = true;
|
raster@14180
|
95 |
}
|
raster@14180
|
96 |
|
raster@15779
|
97 |
public void run(ParserResult compilationInfo) throws Exception {
|
raster@14180
|
98 |
}
|
raster@14180
|
99 |
|
raster@14523
|
100 |
protected final synchronized boolean isCancelled() {
|
raster@14523
|
101 |
return cancelled;
|
raster@14523
|
102 |
}
|
raster@14523
|
103 |
|
raster@14523
|
104 |
protected final synchronized void resume() {
|
raster@14523
|
105 |
cancelled = false;
|
raster@14523
|
106 |
}
|
raster@14523
|
107 |
|
raster@15779
|
108 |
@Override
|
raster@15779
|
109 |
public void run(Result r, SchedulerEvent event) {
|
raster@15779
|
110 |
resume();
|
raster@14523
|
111 |
|
raster@15779
|
112 |
if (isCancelled()) {
|
raster@15779
|
113 |
return;
|
raster@14523
|
114 |
}
|
raster@15779
|
115 |
|
raster@15779
|
116 |
AdaParseResult result = (AdaParseResult) r;
|
raster@15779
|
117 |
Map<OffsetRange, Set<ColoringAttributes>> highlights =
|
raster@15779
|
118 |
new HashMap<OffsetRange, Set<ColoringAttributes>>(100);
|
raster@15779
|
119 |
|
raster@15779
|
120 |
if (result.getProgram() != null) {
|
raster@15779
|
121 |
result.getProgram().accept(new SemanticHighlightVisitor(highlights, result.getSnapshot()));
|
raster@15779
|
122 |
|
raster@15779
|
123 |
if (highlights.size() > 0) {
|
raster@15779
|
124 |
semanticHighlights = highlights;
|
raster@15779
|
125 |
} else {
|
raster@15779
|
126 |
semanticHighlights = null;
|
raster@15779
|
127 |
}
|
raster@15779
|
128 |
}
|
raster@15779
|
129 |
}
|
raster@15779
|
130 |
|
raster@15779
|
131 |
@Override
|
raster@15779
|
132 |
public int getPriority() {
|
raster@15779
|
133 |
return 0;
|
raster@15779
|
134 |
}
|
raster@15779
|
135 |
|
raster@15779
|
136 |
@Override
|
raster@15779
|
137 |
public Class<? extends Scheduler> getSchedulerClass() {
|
raster@15779
|
138 |
return Scheduler.EDITOR_SENSITIVE_TASK_SCHEDULER;
|
raster@14523
|
139 |
}
|
raster@14523
|
140 |
|
raster@14523
|
141 |
private class SemanticHighlightVisitor extends DefaultVisitor {
|
raster@14523
|
142 |
|
raster@14523
|
143 |
private class IdentifierColoring {
|
raster@14523
|
144 |
|
raster@14523
|
145 |
public Identifier identifier;
|
raster@14523
|
146 |
public Set<ColoringAttributes> coloring;
|
raster@14523
|
147 |
|
raster@14523
|
148 |
public IdentifierColoring(Identifier identifier, Set<ColoringAttributes> coloring) {
|
raster@14523
|
149 |
this.identifier = identifier;
|
raster@14523
|
150 |
this.coloring = coloring;
|
raster@14523
|
151 |
}
|
raster@14523
|
152 |
}
|
raster@14523
|
153 |
Map<OffsetRange, Set<ColoringAttributes>> highlights;
|
raster@14523
|
154 |
// for unused private fields: name, varible
|
raster@14523
|
155 |
// if isused, then it's deleted from the list and marked as the field
|
raster@14523
|
156 |
private final Map<String, IdentifierColoring> privateFieldsUsed;
|
raster@14523
|
157 |
// for unsed private method: name, identifier
|
raster@14523
|
158 |
private final Map<String, IdentifierColoring> privateMethod;
|
raster@14523
|
159 |
// this is holder of blocks, which has to be scanned for usages in the class.
|
raster@14523
|
160 |
private List<Block> needToScan = new ArrayList<Block>();
|
raster@15779
|
161 |
private final Snapshot snapshot;
|
raster@14523
|
162 |
|
raster@15779
|
163 |
public SemanticHighlightVisitor(Map<OffsetRange, Set<ColoringAttributes>> highlights, Snapshot snapshot) {
|
raster@14523
|
164 |
this.highlights = highlights;
|
raster@14523
|
165 |
privateFieldsUsed = new HashMap<String, IdentifierColoring>();
|
raster@14523
|
166 |
privateMethod = new HashMap<String, IdentifierColoring>();
|
raster@15779
|
167 |
this.snapshot = snapshot;
|
raster@14523
|
168 |
}
|
raster@14523
|
169 |
|
raster@14523
|
170 |
private void addOffsetRange(ASTNode node, Set<ColoringAttributes> coloring) {
|
raster@15779
|
171 |
int start = snapshot.getOriginalOffset(node.getStartOffset());
|
raster@15779
|
172 |
if (start > -1) {
|
raster@15779
|
173 |
int end = start + node.getEndOffset() - node.getStartOffset();
|
raster@15779
|
174 |
highlights.put(new OffsetRange(start, end), coloring);
|
raster@14523
|
175 |
}
|
raster@14523
|
176 |
}
|
raster@14523
|
177 |
|
raster@14523
|
178 |
@Override
|
raster@14523
|
179 |
public void visit(PackageSpecification node) {
|
raster@14523
|
180 |
if (isCancelled()) {
|
raster@14523
|
181 |
return;
|
raster@14523
|
182 |
}
|
raster@14523
|
183 |
Identifier name = node.getName();
|
raster@14523
|
184 |
addOffsetRange(name, ColoringAttributes.CLASS_SET);
|
raster@14539
|
185 |
// Check if package name end is present
|
raster@14539
|
186 |
if (node.getNameEnd().getName() != null) {
|
raster@14539
|
187 |
Identifier nameEnd = node.getNameEnd();
|
raster@14539
|
188 |
addOffsetRange(nameEnd, ColoringAttributes.CLASS_SET);
|
raster@14523
|
189 |
}
|
raster@14523
|
190 |
needToScan = new ArrayList<Block>();
|
raster@14539
|
191 |
if (node.getBody() != null) {
|
raster@14539
|
192 |
node.getBody().accept(this);
|
raster@14523
|
193 |
|
raster@14523
|
194 |
// find all usages in the method bodies
|
raster@14523
|
195 |
for (Block block : needToScan) {
|
raster@14523
|
196 |
block.accept(this);
|
raster@14523
|
197 |
}
|
raster@14523
|
198 |
// are there unused private fields?
|
raster@14523
|
199 |
for (IdentifierColoring item : privateFieldsUsed.values()) {
|
raster@14695
|
200 |
addOffsetRange(item.identifier, UNUSED_FIELD_SET);
|
raster@14523
|
201 |
}
|
raster@14523
|
202 |
|
raster@14523
|
203 |
// are there unused private methods?
|
raster@14523
|
204 |
for (IdentifierColoring item : privateMethod.values()) {
|
raster@14695
|
205 |
addOffsetRange(item.identifier, UNUSED_METHOD_SET);
|
raster@14695
|
206 |
}
|
raster@14695
|
207 |
}
|
raster@14695
|
208 |
}
|
raster@14695
|
209 |
|
raster@14695
|
210 |
@Override
|
raster@14539
|
211 |
public void visit(PackageBody node) {
|
raster@14539
|
212 |
if (isCancelled()) {
|
raster@14539
|
213 |
return;
|
raster@14539
|
214 |
}
|
raster@14539
|
215 |
Identifier name = node.getName();
|
raster@14539
|
216 |
addOffsetRange(name, ColoringAttributes.CLASS_SET);
|
raster@14539
|
217 |
// Check if package name end is present
|
raster@14539
|
218 |
if (node.getNameEnd().getName() != null) {
|
raster@14539
|
219 |
Identifier nameEnd = node.getNameEnd();
|
raster@14539
|
220 |
addOffsetRange(nameEnd, ColoringAttributes.CLASS_SET);
|
raster@14539
|
221 |
}
|
raster@14539
|
222 |
needToScan = new ArrayList<Block>();
|
raster@14539
|
223 |
if (node.getBody() != null) {
|
raster@14539
|
224 |
node.getBody().accept(this);
|
raster@14539
|
225 |
|
raster@14539
|
226 |
// find all usages in the method bodies
|
raster@14539
|
227 |
for (Block block : needToScan) {
|
raster@14539
|
228 |
block.accept(this);
|
raster@14539
|
229 |
}
|
raster@14539
|
230 |
// are there unused private fields?
|
raster@14539
|
231 |
for (IdentifierColoring item : privateFieldsUsed.values()) {
|
raster@14695
|
232 |
addOffsetRange(item.identifier, UNUSED_FIELD_SET);
|
raster@14539
|
233 |
}
|
raster@14539
|
234 |
|
raster@14539
|
235 |
// are there unused private methods?
|
raster@14539
|
236 |
for (IdentifierColoring item : privateMethod.values()) {
|
raster@14695
|
237 |
addOffsetRange(item.identifier, UNUSED_METHOD_SET);
|
raster@14539
|
238 |
}
|
raster@14539
|
239 |
}
|
raster@14539
|
240 |
}
|
raster@14539
|
241 |
|
raster@14539
|
242 |
@Override
|
raster@16367
|
243 |
public void visit(MethodDeclaration method) {
|
raster@16367
|
244 |
if (isCancelled()) {
|
raster@16367
|
245 |
return;
|
raster@16367
|
246 |
}
|
raster@16367
|
247 |
|
raster@16367
|
248 |
boolean isPrivate = Modifier.isPrivate(method.getModifier());
|
raster@16367
|
249 |
EnumSet<ColoringAttributes> coloring = ColoringAttributes.METHOD_SET;
|
raster@16367
|
250 |
|
raster@16367
|
251 |
Identifier identifier = method.getSubrogramName();
|
raster@16367
|
252 |
addOffsetRange(identifier, coloring);
|
raster@16367
|
253 |
if (!method.isSpefication()) {
|
raster@16367
|
254 |
Identifier nameEnd = method.getSubrogramNameEnd();
|
raster@16367
|
255 |
if (nameEnd != null) {
|
raster@16367
|
256 |
addOffsetRange(nameEnd, coloring);
|
raster@16367
|
257 |
}
|
raster@16367
|
258 |
}
|
raster@16367
|
259 |
|
raster@16367
|
260 |
if (method.getSubprogramBody() != null) {
|
raster@16367
|
261 |
// don't scan the body now. It should be scanned after all declarations
|
raster@16367
|
262 |
// are known
|
raster@16367
|
263 |
Block declarations = method.getSubprogramBody().getDeclarations();
|
raster@16367
|
264 |
if (declarations != null) {
|
raster@16367
|
265 |
declarations.accept(this);
|
raster@16367
|
266 |
}
|
raster@16367
|
267 |
Block body = method.getSubprogramBody().getBody();
|
raster@16367
|
268 |
if (body != null) {
|
raster@16367
|
269 |
body.accept(this);
|
raster@16367
|
270 |
}
|
raster@16367
|
271 |
}
|
raster@16367
|
272 |
}
|
raster@16367
|
273 |
|
raster@16367
|
274 |
// @Override
|
raster@16367
|
275 |
// public void visit(BlockStatement block) {
|
raster@16367
|
276 |
// System.out.println("BlockStatement");
|
raster@16367
|
277 |
// if (block.getLabel() != null) {
|
raster@16367
|
278 |
// EnumSet<ColoringAttributes> coloring = ColoringAttributes.METHOD_SET;
|
raster@16367
|
279 |
// Identifier identifier = block.getLabel();
|
raster@16367
|
280 |
// addOffsetRange(identifier, coloring);
|
raster@16367
|
281 |
// }
|
raster@16367
|
282 |
//
|
raster@16367
|
283 |
// // don't scan the body now. It should be scanned after all declarations
|
raster@16367
|
284 |
// // are known
|
raster@16367
|
285 |
// Block declarations = block.getDeclarations();
|
raster@16367
|
286 |
// if (declarations != null) {
|
raster@16367
|
287 |
// needToScan.add(declarations);
|
raster@16367
|
288 |
// }
|
raster@16367
|
289 |
// Block body = block.getBody();
|
raster@16367
|
290 |
// if (body != null) {
|
raster@16367
|
291 |
// needToScan.add(body);
|
raster@16367
|
292 |
// }
|
raster@16367
|
293 |
// }
|
raster@16367
|
294 |
|
raster@16367
|
295 |
@Override
|
raster@14539
|
296 |
public void visit(FieldsDeclaration node) {
|
raster@14539
|
297 |
if (isCancelled()) {
|
raster@14539
|
298 |
return;
|
raster@14539
|
299 |
}
|
raster@14539
|
300 |
|
raster@14695
|
301 |
boolean isPrivate = Modifier.isPrivate(node.getModifier());
|
raster@14539
|
302 |
EnumSet<ColoringAttributes> coloring = ColoringAttributes.FIELD_SET;
|
raster@14539
|
303 |
|
raster@14539
|
304 |
Variable[] variables = node.getVariableNames();
|
raster@14539
|
305 |
for (int i = 0; i < variables.length; i++) {
|
raster@14539
|
306 |
Variable variable = variables[i];
|
raster@14695
|
307 |
if (!isPrivate) {
|
raster@14695
|
308 |
addOffsetRange(variable.getName(), ColoringAttributes.FIELD_SET);
|
raster@14695
|
309 |
} else {
|
raster@14695
|
310 |
if (variable.getName() instanceof Identifier) {
|
raster@14720
|
311 |
Identifier identifier = (Identifier) variable.getName();
|
raster@14695
|
312 |
privateFieldsUsed.put(identifier.getName(), new IdentifierColoring(identifier, coloring));
|
raster@14695
|
313 |
}
|
raster@14539
|
314 |
}
|
raster@16367
|
315 |
if (variable.getVariableType() != null) {
|
raster@16367
|
316 |
TypeName typeName = variable.getVariableType();
|
raster@16367
|
317 |
typeName.accept(this);
|
raster@16367
|
318 |
}
|
raster@14539
|
319 |
}
|
raster@14539
|
320 |
}
|
raster@14695
|
321 |
|
raster@14695
|
322 |
@Override
|
raster@14695
|
323 |
public void visit(TypeDeclaration node) {
|
raster@14695
|
324 |
if (isCancelled()) {
|
raster@14695
|
325 |
return;
|
raster@14695
|
326 |
}
|
raster@14695
|
327 |
|
raster@14695
|
328 |
boolean isPrivate = Modifier.isPrivate(node.getModifier());
|
raster@14695
|
329 |
EnumSet<ColoringAttributes> coloring = ColoringAttributes.FIELD_SET;
|
raster@14695
|
330 |
|
raster@14695
|
331 |
Identifier id = node.getTypeName();
|
raster@14695
|
332 |
if (!isPrivate) {
|
raster@14695
|
333 |
addOffsetRange(id, ColoringAttributes.FIELD_SET);
|
raster@14695
|
334 |
} else {
|
raster@14695
|
335 |
privateFieldsUsed.put(id.getName(), new IdentifierColoring(id, coloring));
|
raster@14695
|
336 |
}
|
raster@14695
|
337 |
}
|
raster@16367
|
338 |
|
raster@16367
|
339 |
@Override
|
raster@16367
|
340 |
public void visit(Variable node) {
|
raster@16367
|
341 |
if (isCancelled()) {
|
raster@16367
|
342 |
return;
|
raster@16367
|
343 |
}
|
raster@16367
|
344 |
|
raster@16367
|
345 |
Identifier id = node.getName();
|
raster@16367
|
346 |
addOffsetRange(id, ColoringAttributes.FIELD_SET);
|
raster@16367
|
347 |
}
|
raster@16367
|
348 |
|
raster@16367
|
349 |
@Override
|
raster@16367
|
350 |
public void visit(TypeName node) {
|
raster@16367
|
351 |
if (isCancelled()) {
|
raster@16367
|
352 |
return;
|
raster@16367
|
353 |
}
|
raster@16367
|
354 |
|
raster@16367
|
355 |
if (node.isIsBaseType() == false) {
|
raster@16367
|
356 |
Identifier id = node.getTypeName();
|
raster@16367
|
357 |
addOffsetRange(id, ColoringAttributes.FIELD_SET);
|
raster@16367
|
358 |
}
|
raster@16367
|
359 |
}
|
raster@14523
|
360 |
}
|
raster@14180
|
361 |
}
|