Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 5f3ee4312746fe6e3d7d66aac1d20b8ab1ff78a5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
/*******************************************************************************
 * Copyright (c) 2007 University of Illinois at Urbana-Champaign and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     UIUC - Initial API and implementation
 *******************************************************************************/
package org.eclipse.photran.core.vpg;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.cdt.core.CCProjectNature;
import org.eclipse.cdt.core.CProjectNature;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.photran.core.FortranAST;
import org.eclipse.photran.core.IFortranAST;
import org.eclipse.photran.internal.core.analysis.binding.Definition;
import org.eclipse.photran.internal.core.analysis.binding.DefinitionCollector;
import org.eclipse.photran.internal.core.analysis.binding.ImplicitSpecCollector;
import org.eclipse.photran.internal.core.analysis.binding.ModuleLoader;
import org.eclipse.photran.internal.core.analysis.binding.ReferenceCollector;
import org.eclipse.photran.internal.core.analysis.binding.SpecificationCollector;
import org.eclipse.photran.internal.core.analysis.types.Type;
import org.eclipse.photran.internal.core.lexer.IAccumulatingLexer;
import org.eclipse.photran.internal.core.lexer.IncludeLoaderCallback;
import org.eclipse.photran.internal.core.lexer.LexerFactory;
import org.eclipse.photran.internal.core.lexer.SourceForm;
import org.eclipse.photran.internal.core.lexer.Token;
import org.eclipse.photran.internal.core.parser.Parser;

import bz.over.vpg.TokenRef;
import bz.over.vpg.VPGDependency;
import bz.over.vpg.eclipse.EclipseVPG;

/**
 * Photran's Virtual Program Graph.
 * 
 * @author Jeff Overbey
 */
public class PhotranVPG extends EclipseVPG<IFortranAST, Token>
{
	// Copied from FortranCorePlugin to avoid dependencies on the Photran Core plug-in
	// (since our parser declares classes with the same name)
    public static final String FIXED_FORM_CONTENT_TYPE = "org.eclipse.photran.core.fixedFormFortranSource";
    public static final String FREE_FORM_CONTENT_TYPE = "org.eclipse.photran.core.freeFormFortranSource";
    
	public static final int DEFINED_IN_SCOPE_EDGE_TYPE = 0;
	public static final int IMPORTED_INTO_SCOPE_EDGE_TYPE = 1;
	public static final int BINDING_EDGE_TYPE = 2;
	public static final int RENAMED_BINDING_EDGE_TYPE = 3;
	
	private static final String[] edgeTypeDescriptions = { "Definition-scope relationship", "Definition-scope relationship due to module import", "Binding", "Renamed binding" };
	
	public static final int SCOPE_DEFAULT_VISIBILITY_IS_PRIVATE_ANNOTATION_TYPE = 0;
	public static final int SCOPE_IS_INTERNAL_ANNOTATION_TYPE = 1;
	public static final int SCOPE_IMPLICIT_SPEC_ANNOTATION_TYPE = 2;
	public static final int DEFINITION_ANNOTATION_TYPE = 3;
	public static final int TYPE_ANNOTATION_TYPE = 4;
	
	private static final String[] annotationTypeDescriptions = { "Default visibility for scope is private",
	                                                             "Implicit spec for scope",
	                                                             "Definition",
	                                                             "Type" };
	
	private static PhotranVPG instance = null;
	
	public static PhotranVPG getInstance()
	{
		if (instance == null) instance = new PhotranVPGBuilder();
		return instance;
	}
	
	@Override public void start()
	{
		if (!inTestingMode()) super.start();
	}

	protected PhotranVPG()
	{
        super(inTestingMode() ? createTempFile() : Activator.getDefault().getStateLocation().addTrailingSeparator().toOSString() + "vpg",
              "Synchronizing Photran VPG");
    }
	
	private static String createTempFile()
    {
	    try
        {
            File f = File.createTempFile("vpg", null);
            f.deleteOnExit();
            return f.getAbsolutePath();
        }
        catch (IOException e)
        {
            throw new Error(e);
        }
    }

    public static boolean inTestingMode()
	{
		return System.getenv("TESTING") != null;
	}

	@Override
	protected boolean shouldProcessFile(IFile file)
	{
		String filename = file.getName();
		return hasFixedFormContentType(filename) || hasFreeFormContentType(filename);
	}
	
	private static boolean hasFixedFormContentType(String filename)
	{
		if (inTestingMode()) // Fortran content types not set in testing workspace
			return filename.endsWith(".f");
		else
			return FIXED_FORM_CONTENT_TYPE.equals(getContentType(filename));
	}
	
	private static boolean hasFreeFormContentType(String filename)
	{
		if (inTestingMode()) // Fortran content types not set in testing workspace
			return filename.endsWith(".f90");
		else
			return FREE_FORM_CONTENT_TYPE.equals(getContentType(filename));
	}
	
	private static final String getContentType(String filename)
	{
		IContentType contentType = Platform.getContentTypeManager().findContentTypeFor(filename);
		return contentType == null ? null : contentType.getId();
		
		// In CDT, return CoreModel.getRegistedContentTypeId(file.getProject(), file.getName());
	}

	@Override
	protected boolean shouldProcessProject(IProject project)
	{
		try
		{
			return project.hasNature(CProjectNature.C_NATURE_ID) || project.hasNature(CCProjectNature.CC_NATURE_ID);
		}
		catch (CoreException e)
		{
			throw new Error(e);
		}
	}
	
	@Override protected byte[] serialize(Serializable annotation) throws IOException
	{
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		new ObjectOutputStream(out).writeObject(annotation);
		return out.toByteArray();
	}
	
	@Override protected Serializable deserialize(InputStream binaryStream) throws IOException, ClassNotFoundException
	{
		return (Serializable)new ObjectInputStream(binaryStream).readObject();
	}

	protected String describeEdgeType(int edgeType)
	{
		return edgeTypeDescriptions[edgeType];
	}

	protected String describeAnnotationType(int annotationType)
	{
		return annotationTypeDescriptions[annotationType];
	}

	protected String describeToken(String filename, int offset, int length)
	{
		try
		{
			if (offset == -1 && length == 0) return "global scope";
			
			Token token = acquireTransientAST(filename).findTokenByStreamOffsetLength(offset, length);
			if (token == null)
				return super.describeToken(filename, offset, length);
			else
				return token.getText() + " (offset " + offset + ")";
		}
		catch (Exception e)
		{
			return super.describeToken(filename, offset, length);
		}
	}
	
	@Override public TokenRef<Token> createTokenRef(String filename, int offset, int length)
	{
		return new PhotranTokenRef(filename, offset, length);
	}

	@Override
	protected long getModificationStamp(String filename)
	{
		if (filename.startsWith("module:")) return Long.MIN_VALUE;
		
		return getIFileForFilename(filename).getLocalTimeStamp();
	}

	@Override
	public Token findToken(TokenRef<Token> tokenRef)
	{
		IFortranAST ast = acquireTransientAST(tokenRef.getFilename());
		if (ast == null)
			return null;
		else
			return ast.findTokenByFileOffsetLength(getIFileForFilename(tokenRef.getFilename()), tokenRef.getOffset(), tokenRef.getLength());
	}

	@Override
	protected TokenRef<Token> getTokenRef(Token forToken)
	{
		return forToken.getTokenRef();
	}
	
	@Override
	protected IFortranAST parse(final String filename)
	{
		if (filename.startsWith("module:")) return null;
		
		IFile file = getIFileForFilename(filename);

		IContentType contentType2 = Platform.getContentTypeManager().findContentTypeFor(filename);
		String contentType = contentType2 == null ? null : contentType2.getId();
		// In CDT, String contentType = CoreModel.getRegistedContentTypeId(file.getProject(), file.getName());

		SourceForm sourceForm;
		if (contentType != null && contentType.equals(FIXED_FORM_CONTENT_TYPE))
			sourceForm = SourceForm.FIXED_FORM;
		else
		{
			sourceForm = SourceForm.preprocessedFreeForm(new IncludeLoaderCallback(file.getProject())
			{
				@Override
				public InputStream getIncludedFileAsStream(String fileToInclude) throws FileNotFoundException
				{
					// When we encounter an INCLUDE directive, set up a file dependency in the VPG
					
					ensure(new VPGDependency<IFortranAST, Token>(PhotranVPG.this,
								filename,
								getFilenameForIFile(getIncludedFile(fileToInclude))));
					
					return super.getIncludedFileAsStream(fileToInclude);
				}
			});
		}

		try
		{
			IAccumulatingLexer lexer = LexerFactory.createLexer(file, sourceForm);
			return new FortranAST(file, new Parser().parse(lexer), lexer.getTokenList());
		}
		catch (Exception e)
		{
			logError(e);
			return null;
		}
	}

	@Override
	protected void populateVPG(String filename, IFortranAST ast)
	{
		if (!filename.startsWith("module:"))
		{
			deleteAllIncomingDependenciesFor(filename);
			deleteAllOutgoingDependenciesFor(filename);
		}
		
		if (ast == null) return;

        long[] t = new long[6];
		t[0] = System.currentTimeMillis();
		ast.visitTopDownUsing(new ImplicitSpecCollector());
        t[1] = System.currentTimeMillis();
		ast.visitBottomUpUsing(new DefinitionCollector(getIFileForFilename(filename)));
        t[2] = System.currentTimeMillis();
		ast.visitBottomUpUsing(new SpecificationCollector());
        t[3] = System.currentTimeMillis();
		ast.visitBottomUpUsing(
			new ModuleLoader(getIFileForFilename(filename),
					new NullProgressMonitor()));
					//PhotranVPG.getInstance().getCurrentProgressMonitor()));
		// TODO: Type check here so derived type components can be resolved
        t[4] = System.currentTimeMillis();
		ast.visitBottomUpUsing(new ReferenceCollector());
        t[5] = System.currentTimeMillis();

//        String s = "";
//        for (int i = 1; i < t.length; i++)
//            s += (t[i] - t[i-1]) + " ";
//        System.out.println(s);
	}
	
	public IFortranAST acquireTransientAST(IFile file)
	{
		return acquireTransientAST(getFilenameForIFile(file));
	}
	
	public IFortranAST acquirePermanentAST(IFile file)
	{
		return acquirePermanentAST(getFilenameForIFile(file));
	}
	
	public void releaseAST(IFile file)
	{
		releaseAST(getFilenameForIFile(file));
	}

	public static String canonicalizeIdentifier(String moduleName)
	{
		return moduleName.trim().toLowerCase().replaceAll("[ \t\r\n]", "");
	}

	public List<IFile> findFilesThatExportModule(String moduleName)
	{
		List<IFile> files = new LinkedList<IFile>();
		for (String filename : getOutgoingDependenciesFrom("module:" + canonicalizeIdentifier(moduleName)))
		{
			IFile file = getIFileForFilename(filename);
			if (file == null)
			{
				System.err.println("************** CAN'T MAP " + filename + " TO AN IFILE");
				try {
					ResourcesPlugin.getWorkspace().getRoot().accept(new IResourceVisitor()
					{
						public boolean visit(IResource resource) throws CoreException
						{
							System.err.println(resource.getFullPath().toOSString());
							return true;
						}
						
					});
				} catch (CoreException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if (file != null) files.add(file);
		}
		return files;
	}
	
	public Definition getDefinitionFor(TokenRef<Token> tokenRef)
	{
		return (Definition)getAnnotation(tokenRef, DEFINITION_ANNOTATION_TYPE);
	}
	
	public Type getTypeFor(TokenRef<Token> tokenRef)
	{
		return (Type)getAnnotation(tokenRef, TYPE_ANNOTATION_TYPE);
	}
}

Back to the top