Commit 245a9828 authored by Markus Klinik's avatar Markus Klinik
Browse files

proper error handling when there is no Main class

parent 8d46bbf9
......@@ -21,41 +21,48 @@ set[Message] aStudent_group(M3 model) = assertExists(findClass, model, "Group");
// TODO: we have a helper function for this now
set[Message] aStudent_io(M3 model)
{
// we assume there is only one main method, which lets us identify the main class
loc mainClass = getMainClass(model);
// find all methods that use System
set[loc] ioMethods =
{ m
| m <- invert(model.typeDependency)[|java+class:///java/lang/System|]
, isMethod(m)
};
// find the classes to which these methods belong
set[loc] ioClasses = range(domainR(invert(model.containment), ioMethods));
set[str] ioClassNames = { getName(model, c) | c <- ioClasses };
// Some heuristics. Many students implemented a view class, which doesn't have
// a main function. In this case we don't want to generate an error message.
// Therefore, the rules:
// - If more than one class has I/O: generate messages for both of them
// - If only one class has I/O: check that it is NOT Student or Group.
// More than one class has I/O
if( size(ioClasses) > 1 )
try
{
return
{ error("Only the main or view class should contain I/O", c)
| c <- ioClasses, c != mainClass
// we assume there is only one main method, which lets us identify the main class
loc mainClass = getMainClass(model);
// find all methods that use System
set[loc] ioMethods =
{ m
| m <- invert(model.typeDependency)[|java+class:///java/lang/System|]
, isMethod(m)
};
// find the classes to which these methods belong
set[loc] ioClasses = range(domainR(invert(model.containment), ioMethods));
set[str] ioClassNames = { getName(model, c) | c <- ioClasses };
// Some heuristics. Many students implemented a view class, which doesn't have
// a main function. In this case we don't want to generate an error message.
// Therefore, the rules:
// - If more than one class has I/O: generate messages for both of them
// - If only one class has I/O: check that it is NOT Student or Group.
// More than one class has I/O
if( size(ioClasses) > 1 )
{
return
{ error("Only the main or view class should contain I/O", c)
| c <- ioClasses, c != mainClass
};
}
// Only one class has I/O
else if( "Student" in ioClassNames || "Group" in ioClassNames )
{
return
{ error("Only the main or view class should contain I/O", c)
| c <- ioClasses
};
}
}
// Only one class has I/O
else if( "Student" in ioClassNames || "Group" in ioClassNames )
catch e:error(_,_):
{
return
{ error("Only the main or view class should contain I/O", c)
| c <- ioClasses
};
return { e };
}
return {};
......
......@@ -22,7 +22,15 @@ set[Message] modelErrors(M3 model) =
};
// Assumption: the given identifier has exactly one name.
str getName(M3 model, loc identifier) = getOneFrom(invert(model.names)[identifier]);
str getName(M3 model, loc identifier)
{
set[str] candidateNames = invert(model.names)[identifier];
if(size(candidateNames) < 1)
{
return "<identifier>";
}
return getOneFrom(candidateNames);
}
// A main method is public static and called main. We don't check for arguments.
// Checking argument types is complicated, and probably this catches all cases anyway.
......@@ -34,8 +42,16 @@ set[loc] getMainMethods(M3 model)
}
// Assumes that there is exactly one Main class in the project
loc getMainClass(M3 model) =
getOneFrom(range(domainR(invert(model.containment), getMainMethods(model))));
// Throws an error if there is no Main class
loc getMainClass(M3 model)
{
mainClasses = range(domainR(invert(model.containment), getMainMethods(model)));
if(size(mainClasses) < 1)
{
throw error("There should be a Main class.", |file:///|);
}
return getOneFrom(mainClasses);
}
// extract only the messages of a set of errors, discarding the locations
set[str] messages(set[Message] errors) = { message | error(message, _) <- errors };
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment