001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.cnd.modelimpl.csm.core;
043:
044: import java.util.HashMap;
045: import java.util.HashSet;
046: import java.util.List;
047: import java.util.Map;
048: import java.util.Set;
049: import org.netbeans.modules.cnd.api.model.CsmFile;
050: import org.netbeans.modules.cnd.api.model.CsmInclude;
051: import org.netbeans.modules.cnd.api.project.NativeFileItem;
052: import org.netbeans.modules.cnd.apt.support.APTPreprocHandler;
053: import org.netbeans.modules.cnd.modelimpl.debug.DiagnosticExceptoins;
054: import org.netbeans.modules.cnd.modelimpl.debug.TraceFlags;
055:
056: /**
057: * Reparse dependant files.
058: * @author Alexander Simon
059: */
060: public final class DeepReparsingUtils {
061:
062: private DeepReparsingUtils() {
063: }
064:
065: /**
066: * Reparse including/included files at fileImpl content changed.
067: */
068: public static void reparseOnEdit(FileImpl fileImpl,
069: ProjectBase project) {
070: reparseOnEdit(fileImpl, project, true);
071: }
072:
073: /**
074: * Reparse including/included files at fileImpl content changed.
075: */
076: public static void reparseOnEdit(FileImpl fileImpl,
077: ProjectBase project, boolean scheduleParsing) {
078: Set<CsmFile> topParents = project.getGraph().getTopParentFiles(
079: fileImpl);
080: if (topParents.size() > 0) {
081: Set<CsmFile> coherence = project.getGraph()
082: .getCoherenceFiles(fileImpl);
083: for (CsmFile parent : coherence) {
084: if (!topParents.contains(parent)) {
085: invalidateFileAndPreprocState(project, parent);
086: }
087: }
088: if (scheduleParsing) {
089: // coherence already invalidated, pass empty set
090: addToReparse(project, topParents, new HashSet(0), false);
091: }
092: } else {
093: if (scheduleParsing) {
094: ParserQueue.instance().addFirst(
095: fileImpl,
096: project.getPreprocHandler(
097: fileImpl.getBuffer().getFile())
098: .getState(), false);
099: }
100: }
101: }
102:
103: /**
104: * Reparse including/included files at file properties changed.
105: */
106: public static void reparseOnPropertyChanged(
107: NativeFileItem nativeFile, ProjectBase project) {
108: FileImpl file = project.getFile(nativeFile.getFile());
109: if (file == null) {
110: return;
111: }
112: if (TraceFlags.USE_DEEP_REPARSING) {
113: Set<CsmFile> top = project.getGraph().getTopParentFiles(
114: file);
115: Set<CsmFile> coherence = project.getGraph()
116: .getIncludedFiles(file);
117: for (CsmFile parent : coherence) {
118: if (!top.contains(parent)) {
119: invalidateFileAndPreprocState(project, parent);
120: }
121: }
122: addToReparse(project, nativeFile, file);
123: top.remove(file);
124: // coherence already invalidated, pass empty set
125: addToReparse(project, top, new HashSet(0), false);
126: } else {
127: addToReparse(project, nativeFile, file);
128: }
129: }
130:
131: /**
132: * Reparse including/included files at file properties changed.
133: */
134: public static void reparseOnPropertyChanged(
135: List<NativeFileItem> items, ProjectImpl project) {
136: try {
137: ParserQueue.instance().onStartAddingProjectFiles(project);
138: if (TraceFlags.USE_DEEP_REPARSING) {
139: Map<FileImpl, NativeFileItem> pairs = new HashMap<FileImpl, NativeFileItem>();
140: Set<CsmFile> top = new HashSet<CsmFile>();
141: Set<CsmFile> coherence = new HashSet<CsmFile>();
142: for (NativeFileItem item : items) {
143: if (project.acceptNativeItem(item)) {
144: FileImpl file = project.getFile(item.getFile());
145: if (file != null) {
146: pairs.put(file, item);
147: top.addAll(project.getGraph()
148: .getTopParentFiles(file));
149: coherence.addAll(project.getGraph()
150: .getIncludedFiles(file));
151: }
152: }
153: }
154: for (CsmFile parent : coherence) {
155: if (!top.contains(parent)) {
156: invalidateFileAndPreprocState(project, parent);
157: }
158: }
159: for (CsmFile parent : top) {
160: if (parent.getProject() == project) {
161: FileImpl parentImpl = (FileImpl) parent;
162: if (pairs.containsKey(parentImpl)) {
163: NativeFileItem item = pairs.get(parentImpl);
164: addToReparse(project, item, parentImpl);
165: } else {
166: addToReparse(project, parentImpl, true);
167: }
168: }
169: }
170: } else {
171: for (NativeFileItem item : items) {
172: FileImpl file = project.getFile(item.getFile());
173: if (file != null) {
174: addToReparse(project, item, file);
175: }
176: }
177: }
178: } catch (Exception e) {
179: DiagnosticExceptoins.register(e);
180: } finally {
181: ParserQueue.instance().onEndAddingProjectFiles(project);
182: }
183: }
184:
185: /**
186: * Reparse included files at file added.
187: */
188: public static void reparseOnAdded(NativeFileItem nativeFile,
189: ProjectBase project) {
190: if (!TraceFlags.USE_DEEP_REPARSING) {
191: return;
192: }
193: String name = nativeFile.getFile().getName();
194: Set<CsmFile> resolved = new HashSet<CsmFile>();
195: for (CsmFile file : project.getSourceFiles()) {
196: for (CsmInclude incl : file.getIncludes()) {
197: if (incl.getIncludeName().toString().endsWith(name)/* && incl.getIncludeFile() == null*/) {
198: resolved.add(file);
199: break;
200: }
201: }
202: }
203: if (resolved.size() > 0) {
204: Set<CsmFile> top = new HashSet<CsmFile>();
205: Set<CsmFile> coherence = new HashSet<CsmFile>();
206: for (CsmFile file : resolved) {
207: top.addAll(project.getGraph().getTopParentFiles(file));
208: coherence.addAll(project.getGraph().getIncludedFiles(
209: file));
210: }
211: addToReparse(project, top, coherence, true);
212: }
213: }
214:
215: static void reparseOnAdded(List<NativeFileItem> toReparse,
216: ProjectBase project) {
217: if (!TraceFlags.USE_DEEP_REPARSING) {
218: return;
219: }
220: Set<String> names = new HashSet<String>();
221: for (NativeFileItem item : toReparse) {
222: names.add(item.getFile().getName());
223: }
224: Set<CsmFile> resolved = new HashSet<CsmFile>();
225: for (CsmFile file : project.getSourceFiles()) {
226: findResolved(names, resolved, file);
227: }
228: for (CsmFile file : project.getHeaderFiles()) {
229: findResolved(names, resolved, file);
230: }
231: if (resolved.size() > 0) {
232: Set<CsmFile> top = new HashSet<CsmFile>();
233: Set<CsmFile> coherence = new HashSet<CsmFile>();
234: for (CsmFile file : resolved) {
235: top.addAll(project.getGraph().getTopParentFiles(file));
236: coherence.addAll(project.getGraph().getIncludedFiles(
237: file));
238: }
239: addToReparse(project, top, coherence, true);
240: }
241: }
242:
243: private static void findResolved(final Set<String> names,
244: final Set<CsmFile> resolved, final CsmFile file) {
245: for (CsmInclude incl : file.getIncludes()) {
246: String name = incl.getIncludeName().toString();
247: int i = Math.max(name.lastIndexOf('\\'), name
248: .lastIndexOf('/'));
249: if (i > 0) {
250: name = name.substring(i);
251: }
252: if (names.contains(name)) {
253: resolved.add(file);
254: break;
255: }
256: }
257: }
258:
259: /**
260: * Reparse including/included files at file removed.
261: */
262: public static void reparseOnRemoved(FileImpl impl,
263: ProjectBase project) {
264: if (!TraceFlags.USE_DEEP_REPARSING) {
265: return;
266: }
267: Set<CsmFile> topParents = project.getGraph().getTopParentFiles(
268: impl);
269: Set<CsmFile> coherence = project.getGraph().getCoherenceFiles(
270: impl);
271: project.getGraph().removeFile(impl);
272: topParents.remove(impl);
273: coherence.remove(impl);
274: addToReparse(project, topParents, coherence, false);
275: }
276:
277: static void reparseOnRemoved(List<FileImpl> toReparse,
278: ProjectBase project) {
279: if (!TraceFlags.USE_DEEP_REPARSING) {
280: return;
281: }
282: Set<CsmFile> topParents = new HashSet<CsmFile>();
283: Set<CsmFile> coherence = new HashSet<CsmFile>();
284: for (FileImpl impl : toReparse) {
285: topParents.addAll(project.getGraph()
286: .getTopParentFiles(impl));
287: coherence
288: .addAll(project.getGraph().getCoherenceFiles(impl));
289: project.getGraph().removeFile(impl);
290: topParents.remove(impl);
291: coherence.remove(impl);
292: }
293: addToReparse(project, topParents, coherence, false);
294: }
295:
296: private static void addToReparse(final ProjectBase project,
297: final Set<CsmFile> topParents,
298: final Set<CsmFile> coherence, boolean invalidateCache) {
299: for (CsmFile incl : coherence) {
300: if (!topParents.contains(incl)) {
301: invalidateFileAndPreprocState(project, incl);
302: }
303: }
304: boolean progress = false;
305: try {
306: if (topParents.size() > 5) {
307: ParserQueue.instance().onStartAddingProjectFiles(
308: project);
309: progress = true;
310: }
311: for (CsmFile parent : topParents) {
312: if (parent.getProject() == project) {
313: FileImpl parentImpl = (FileImpl) parent;
314: addToReparse(project, parentImpl, invalidateCache);
315: }
316: }
317: } catch (Exception e) {
318: DiagnosticExceptoins.register(e);
319: } finally {
320: if (progress) {
321: ParserQueue.instance().onEndAddingProjectFiles(project);
322: }
323: }
324: }
325:
326: private static void addToReparse(final ProjectBase project,
327: final FileImpl parentImpl, final boolean invalidateCache) {
328: parentImpl.stateChanged(invalidateCache);
329: ParserQueue.instance().addFirst(
330: parentImpl,
331: project.getPreprocHandler(
332: parentImpl.getBuffer().getFile()).getState(),
333: false);
334: if (TraceFlags.USE_DEEP_REPARSING_TRACE) {
335: System.out.println("Add file to reparse "
336: + parentImpl.getAbsolutePath()); // NOI18N
337: }
338: }
339:
340: private static void addToReparse(final ProjectBase project,
341: final NativeFileItem nativeFile, final FileImpl file) {
342: file.stateChanged(true);
343: APTPreprocHandler.State state = project
344: .setChangedFileState(nativeFile);
345: if (TraceFlags.USE_DEEP_REPARSING_TRACE) {
346: System.out.println("Add file to reparse "
347: + file.getAbsolutePath()); // NOI18N
348: }
349: ParserQueue.instance().addFirst(file, state, false);
350: }
351:
352: private static void invalidateFileAndPreprocState(
353: final ProjectBase project, final CsmFile parent) {
354: if (parent.getProject() == project) {
355: FileImpl parentImpl = (FileImpl) parent;
356: project.invalidatePreprocState(parentImpl.getBuffer()
357: .getFile());
358: parentImpl.stateChanged(false);
359: if (TraceFlags.USE_DEEP_REPARSING_TRACE) {
360: System.out.println("Invalidate file to reparse "
361: + parent.getAbsolutePath()); // NOI18N
362: }
363: }
364: }
365: }
|