mirror of
https://github.com/chylex/Code-Statistics.git
synced 2024-11-24 12:42:46 +01:00
217 lines
8.3 KiB
C#
217 lines
8.3 KiB
C#
using System.Collections.Generic;
|
|
using CodeStatisticsCore.Input;
|
|
using LanguageJava.Elements;
|
|
using LanguageJava.Utils;
|
|
|
|
namespace LanguageJava.Handling{
|
|
public class JavaState{
|
|
private readonly Dictionary<File, JavaFileInfo> fileInfo = new Dictionary<File, JavaFileInfo>();
|
|
private readonly HashSet<string> packages = new HashSet<string>();
|
|
|
|
public readonly JavaGlobalInfo GlobalInfo = new JavaGlobalInfo();
|
|
|
|
public int PackageCount { get { return packages.Count; } }
|
|
|
|
public JavaFileInfo GetFile(File file){
|
|
return fileInfo[file];
|
|
}
|
|
|
|
public JavaFileInfo Process(File file){
|
|
JavaFileInfo info = new JavaFileInfo();
|
|
fileInfo.Add(file, info);
|
|
|
|
JavaCodeParser parser = new JavaCodeParser(JavaParseUtils.PrepareCodeFile(file.Contents));
|
|
parser.AnnotationCallback += IncrementAnnotation;
|
|
parser.CodeBlockCallback += blockParser => ReadCodeBlock(blockParser, GlobalInfo);
|
|
|
|
ReadPackage(parser, info);
|
|
ReadImportList(parser, info);
|
|
ReadTopLevelTypes(parser, info);
|
|
|
|
UpdateLocalData(info);
|
|
|
|
return info;
|
|
}
|
|
|
|
private void UpdateLocalData(JavaFileInfo info){
|
|
packages.Add(info.Package);
|
|
|
|
foreach(Type type in info.Types){
|
|
UpdateLocalDataForType(type);
|
|
}
|
|
}
|
|
|
|
private void UpdateLocalDataForType(Type type){
|
|
foreach(Type nestedType in type.NestedTypes){
|
|
UpdateLocalDataForType(nestedType);
|
|
}
|
|
|
|
foreach(Field field in type.GetData().Fields){
|
|
GlobalInfo.FieldTypes.Increment(field.Type.ToStringGeneral());
|
|
}
|
|
|
|
foreach(Method method in type.GetData().Methods){
|
|
GlobalInfo.MethodReturnTypes.Increment(method.ReturnType.ToStringGeneral());
|
|
|
|
foreach(TypeOf parameterType in method.ParameterTypes){
|
|
GlobalInfo.MethodParameterTypes.Increment(parameterType.ToStringGeneral());
|
|
}
|
|
}
|
|
}
|
|
|
|
private void IncrementAnnotation(Annotation annotation){
|
|
GlobalInfo.AnnotationUses.Increment(annotation.SimpleName);
|
|
}
|
|
|
|
private static void ReadPackage(JavaCodeParser parser, JavaFileInfo info){
|
|
parser.SkipSpaces();
|
|
parser.SkipReadAnnotationList();
|
|
parser.SkipSpaces();
|
|
|
|
info.Package = parser.ReadPackageDeclaration();
|
|
}
|
|
|
|
private static void ReadImportList(JavaCodeParser parser, JavaFileInfo info){
|
|
while(true){
|
|
parser.SkipSpaces();
|
|
|
|
Import? import = parser.ReadImportDeclaration();
|
|
if (!import.HasValue)break;
|
|
|
|
info.Imports.Add(import.Value);
|
|
}
|
|
}
|
|
|
|
private static void ReadTopLevelTypes(JavaCodeParser parser, JavaFileInfo info){
|
|
while(true){
|
|
parser.SkipSpaces();
|
|
if (parser.IsEOF)break;
|
|
|
|
Type type = parser.ReadType();
|
|
|
|
if (type != null)info.Types.Add(type);
|
|
else break;
|
|
}
|
|
}
|
|
|
|
private static void ReadCodeBlock(JavaCodeBlockParser blockParser, JavaGlobalInfo info){
|
|
string keyword;
|
|
|
|
while((keyword = blockParser.ReadNextKeywordSkip()).Length > 0){
|
|
switch(keyword){
|
|
case "do":
|
|
ReadCodeBlock((JavaCodeBlockParser)blockParser.ReadBlock('{', '}'), info);
|
|
|
|
if (blockParser.ReadNextKeywordSkip() != "while"){
|
|
blockParser.RevertKeywordSkip(); // should not happen
|
|
}
|
|
|
|
++info.Statements[FlowStatement.DoWhile];
|
|
break;
|
|
|
|
case "while":
|
|
++info.Statements[FlowStatement.While];
|
|
break;
|
|
|
|
case "for":
|
|
JavaCodeBlockParser cycleDeclBlock = (JavaCodeBlockParser)blockParser.ReadBlock('(', ')');
|
|
ReadCodeBlock(cycleDeclBlock, info);
|
|
|
|
JavaCodeParser cycleDeclParser = new JavaCodeParser(cycleDeclBlock.Contents);
|
|
cycleDeclParser.ReadTypeOf(false);
|
|
cycleDeclParser.SkipSpaces().ReadIdentifier();
|
|
|
|
++info.Statements[cycleDeclParser.SkipSpaces().Char == ':' ? FlowStatement.EnhancedFor : FlowStatement.For];
|
|
break;
|
|
|
|
case "switch":
|
|
JavaCodeBlockParser switchBlock = (JavaCodeBlockParser)blockParser.ReadBlock('{', '}');
|
|
ReadCodeBlock(switchBlock, info);
|
|
|
|
switchBlock.Reset();
|
|
string switchKeyword;
|
|
int cases = 0;
|
|
|
|
while((switchKeyword = switchBlock.ReadNextKeywordSkip()).Length > 0){
|
|
if (switchKeyword == "switch"){
|
|
switchBlock.SkipBlock('{', '}');
|
|
}
|
|
else if (switchKeyword == "case"){
|
|
++info.Statements[FlowStatement.SwitchCase];
|
|
++cases;
|
|
}
|
|
else if (switchKeyword == "default"){
|
|
++info.Statements[FlowStatement.SwitchDefault]; // TODO count as a case?
|
|
}
|
|
}
|
|
|
|
if (cases < info.MinSwitchCases)info.MinSwitchCases = cases;
|
|
if (cases > info.MaxSwitchCases)info.MaxSwitchCases = cases;
|
|
|
|
++info.Statements[FlowStatement.Switch];
|
|
break;
|
|
|
|
case "try":
|
|
bool isTryWithResources = blockParser.SkipSpaces().Char == '(';
|
|
|
|
ReadCodeBlock((JavaCodeBlockParser)blockParser.ReadBlock('{', '}'), info);
|
|
|
|
string tryKeyword;
|
|
int catches = 0;
|
|
|
|
while((tryKeyword = blockParser.ReadNextKeywordSkip()).Length > 0){
|
|
if (tryKeyword == "catch"){
|
|
++info.Statements[FlowStatement.Catch];
|
|
++catches;
|
|
}
|
|
else if (tryKeyword == "finally"){
|
|
++info.Statements[FlowStatement.Finally];
|
|
|
|
if (isTryWithResources)++info.TryWithResourcesWithFinally;
|
|
else ++info.TryCatchWithFinally;
|
|
}
|
|
else if (tryKeyword != "try"){
|
|
blockParser.RevertKeywordSkip();
|
|
break;
|
|
}
|
|
|
|
ReadCodeBlock((JavaCodeBlockParser)blockParser.ReadBlock('{', '}'), info);
|
|
}
|
|
|
|
if (catches < info.MinCatchBlocks)info.MinCatchBlocks = catches;
|
|
if (catches > info.MaxCatchBlocks)info.MaxCatchBlocks = catches;
|
|
|
|
++info.Statements[isTryWithResources ? FlowStatement.TryWithResources : FlowStatement.TryCatch];
|
|
++info.Statements[FlowStatement.Try];
|
|
break;
|
|
|
|
case "if":
|
|
++info.Statements[FlowStatement.If];
|
|
break;
|
|
|
|
case "else":
|
|
++info.Statements[FlowStatement.Else];
|
|
|
|
if (blockParser.ReadNextKeywordSkip() != "if"){
|
|
blockParser.RevertKeywordSkip();
|
|
}
|
|
|
|
break;
|
|
|
|
case "return":
|
|
++info.Statements[FlowStatement.Return];
|
|
break;
|
|
|
|
case "continue":
|
|
++info.Statements[FlowStatement.Continue];
|
|
break;
|
|
|
|
case "break":
|
|
++info.Statements[FlowStatement.Break];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|